#include "bondratechart.h"
#include <widgets/chart/basechart_plot.h>
#include <widgets/chart/basechart_graph.h>
#include <core/comdefs.h>
#include <core/StyleMgr.h>
#include <widgets/STips.h>
#include <qbtools/tools.h>
#include <uam/ServerTimeMgr.h>

#define min(a,b)            (((a) < (b)) ? (a) : (b))
#define max(a,b)            (((a) > (b)) ? (a) : (b))

namespace qb
{
	BondRateChart::BondRateChart(QWidget* parent)
		: QWidget(parent)
		, mType(type_All)
		, m_lRemain(-1)
		, m_nLinePNum(0)
		, m_nPointNum(0)
		, m_nHotPoint(-1)
		, m_nBegin(0)
		, m_nEnd(0)
		, m_nDealBegin(0)
		, m_nDealEnd(0)
		, m_dMinX(0.0)
		, m_dMaxX(0.0)
		, m_dMinY(0.0)
		, m_dMaxY(0.0)
		, m_dOriginMinX(0.0)
		, m_dOriginMaxX(0.0)
		, m_dDragLeft(0.0)
		, m_dDragRight(0.0)
		, m_dDealDragLeft(0.0)
		, m_dDealDragRight(0.0)
	{
		m_clrInHour.setRgb(0, 128, 253);
		m_clrOutHour.setRgb(0, 223, 85);
	}

	BondRateChart::~BondRateChart()
	{
		StopTimer();
	}

	void BondRateChart::setBondInfo(const CBondInfo* bondinfo)
	{
		if (mBondInfo != bondinfo)
		{
			mBondInfo = (CBondInfo*)bondinfo;

			m_chartDistData.m_Stream.m_list.clear();
			m_chartDistData.m_Stream.m_Record.clear();
			clearCurrentCurve();
		}
	}

	void BondRateChart::loadData(CAnalysisYieldCurve* pYieldCurve, int remain)
	{
		m_lRemain = remain;
		inputData(pYieldCurve);
		refreshData();
	}

	void BondRateChart::loadMktStreamDealData(xQBMarketStreamList_c* pData)
	{
		m_chartDistData.m_Stream.m_list.clear();
		m_chartDistData.m_Stream.m_Record.clear();

		MarketStreamInfo strInfo;
		for (std::list<xQBMarketStreamUnit_c>::const_iterator itr = pData->m_List.begin(); itr != pData->m_List.end(); itr++) {
			DecodeMarketStreamUnit(strInfo, *itr);
			m_chartDistData.m_Stream.m_list.push_back(strInfo);
		}

		refreshData();
	}

	void BondRateChart::setType(emtype type)
	{
		mType = type;
		m_dOriginMinX = 0.0;
		m_dOriginMaxX = 0.0;
	}

	void BondRateChart::setLeftDrag(double ratio)
	{
		QB_CHECK_RETURN_VOID1(customPlot);

		if (type_All == mType)
		{
			if (m_CurveShow.size() <= 0) {
				return;
			}

			double dBegin = ratio * (m_dOriginMaxX - m_dOriginMinX);
			int nBegin = (int)dBegin;
			m_dDragLeft = max(dBegin, m_dOriginMinX + 0.1);
			m_nBegin = max(nBegin, m_dOriginMinX);
		}
		else
		{
			if (m_CurveShow.size() <= 0) {
				return;
			}

			double dBegin = ratio * (m_dOriginMaxX - m_dOriginMinX);
			int nBegin = (int)dBegin;
			m_dDealDragLeft = max(dBegin, m_dOriginMinX + 0.1);
			m_nDealBegin = max(nBegin, m_dOriginMinX);
		}
	}

	void BondRateChart::setRightDrag(double ratio)
	{
		QB_CHECK_RETURN_VOID1(customPlot);

		if (type_All == mType)
		{
			if (m_CurveShow.size() <= 0) {
				return;
			}

			double dEnd = ratio * (m_dOriginMaxX - m_dOriginMinX);
			int nEnd = (int)dEnd;
			m_dDragRight = min(dEnd, m_dOriginMaxX);
			m_nEnd = min(nEnd + 1, m_dOriginMaxX);
		}
		else
		{
			if (m_CurveShow.size() <= 0) {
				return;
			}

			double dEnd = ratio * (m_dOriginMaxX - m_dOriginMinX);
			int nEnd = (int)dEnd;
			m_dDealDragRight = min(dEnd, m_dOriginMaxX);
			m_nDealEnd = min(nEnd + 1, m_dOriginMaxX);
		}
	}

	void BondRateChart::setCentralDrag(double ratio1, double ratio2)
	{
		setLeftDrag(ratio1);
		setRightDrag(ratio2);
	}

	void BondRateChart::createChart()
	{
		verticalLayout = new QVBoxLayout(this);
		customPlot = new BaseChartCustomPlot(this);
		verticalLayout->addWidget(customPlot);
		this->setLayout(verticalLayout);

		if (type_Distribute == mType)
		{
			mTimer = new QTimer(this);
			connect(mTimer, SIGNAL(timeout()), this, SLOT(onTimer()), Qt::UniqueConnection);
			mTimer->setInterval(60000);

			StartTimer();
		}

		connect(customPlot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(onMouseMove(QMouseEvent*)));
		connect(customPlot, &BaseChartCustomPlot::mouseDoubleClick, [=]() { emit mouseDoubleClick(this); });

		QBrush boxBrush(StyleMgr::instance().color("BasicPlate"));
		customPlot->setBackground(boxBrush);
		customPlot->addGraph(customPlot->xAxis, customPlot->yAxis);
		customPlot->xAxis->grid()->setCustomAxisGrid(this);
		customPlot->yAxis->grid()->setCustomAxisGrid(this);
		customPlot->xAxis->setYAxis(customPlot->yAxis);
		customPlot->yAxis->setTickLabelPadding(40);
		customPlot->graph(0)->setPen(QPen(QColor(205, 119, 4)));
		customPlot->graph(0)->setLineStyle(BaseChartGraph::lsLine);
		customPlot->graph(0)->setScatterStyle(BaseChartScatterStyle(BaseChartScatterStyle::ssCircle, 3));

		customPlot->addGraph(customPlot->xAxis, customPlot->yAxis);
		customPlot->graph(1)->setPen(QPen(m_clrOutHour));
		customPlot->graph(1)->setLineStyle(BaseChartGraph::lsNone);
		customPlot->graph(1)->setScatterStyle(BaseChartScatterStyle(BaseChartScatterStyle::ssDisc, 2));

		customPlot->addGraph(customPlot->xAxis, customPlot->yAxis);
		customPlot->graph(2)->setPen(QPen(QColor(0, 128, 253)));
		customPlot->graph(2)->setLineStyle(BaseChartGraph::lsNone);
		customPlot->graph(2)->setScatterStyle(BaseChartScatterStyle(BaseChartScatterStyle::ssDisc, 2));

		customPlot->xAxis->setNumberPrecision(4);
		customPlot->xAxis->setCustomGrid();
		customPlot->yAxis->setCustomGrid();
		customPlot->xAxis->setSubTicks(false);
		customPlot->yAxis->setSubTicks(false);
		customPlot->yAxis->ticker()->setTickCount(4);

		if (type_All == mType)
		{
			QString qText = tr("收益率");
			bcte = new BaseChartTextElement(customPlot, qText, QFont("Microsoft YaHei", 9, QFont::Bold));
		}
		else 
		{
			QString qText1 = tr("当日成交(一小时内)");
			QString qText2 = tr("当日成交(一小时前)");
			bcte = new BaseChartTextElement(customPlot, qText1, qText2, QFont("Microsoft YaHei", 9, QFont::Bold));
		}

		bcte->setCustomDraw(this);
		bcte->setTextFlags(Qt::AlignLeft | Qt::AlignVCenter);
		bcte->setTextOffset(18);
		bcte->setTextColor(StyleMgr::instance().color("TextNormal"));
		customPlot->plotLayout()->addElement(1, 0, bcte);

		bcde = new BaseChartDragBarElement(customPlot);
		customPlot->plotLayout()->addElement(2, 0, bcde);

		refreshData();
	}

	bool BondRateChart::drawGridXLines(BaseChartPainter* painter)
	{
	//	drawMouseMoveLine(painter);

		int num = 0;
		double* x = NULL;
		int flag = 0;
		double m0 = 1.0 / 12;
		double dx = m_dMaxX - m_dMinX;
		if (dx > 40) {
			num = 6;
			x = new double[num];
			x[0] = 4;
			for (int i = 1; i < 6; i++)x[i] = i * 10 + 3;
		}
		else if (dx > 15) {
			num = 11;
			x = new double[num];
			x[0] = 4;
			for (int i = 1; i < 11; i++)x[i] = i * 5 + 3;
		}
		else if (dx > 8) {
			num = 27;
			x = new double[num];
			x[0] = 1.0 / 3;
			for (int i = 1; i < 6; i++)x[i] = i * 2;
			for (int i = 6; i < 27; i++)x[i] = i * 2 + 1;
			flag = 1;
		}
		else if (dx > 2.5) {
			num = 54;
			x = new double[num];
			x[0] = 1.0 / 3;
			for (int i = 1; i < 54; i++)x[i] = i;
			flag = 1;
		}
		else {
			x = new double[12 * 60];
			num = 0;
			for (int i = 0; i < 11; i++) {
				x[num] = (i + 1) / 3.0;
				num++;
			}
			for (int i = 1; i < 53; i++) {
				for (int j = 0; j < 4; j++) {
					x[num] = i + 3 + (j + 1) / 4.0;
					num++;
				}
			}
			flag = 2;
		}

		int top = customPlot->yAxis->axisRect()->top();
		int bottom = customPlot->yAxis->axisRect()->bottom();

		QString szText;
		QFont font("Microsoft YaHei");
		font.setPixelSize(12);
		painter->setFont(font);

		for (int i = 0; i < num; i++)
		{
			int X = customPlot->xAxis->coordToPixel(x[i]);
			if (X >= customPlot->xAxis->axisRect()->left() && X <= customPlot->xAxis->axisRect()->right())
			{
				painter->drawLine(QLineF(X, bottom, X, top));
				switch (flag) {
				case 0:	szText = QString::asprintf("%dY", (int)x[i] - 3);	break;
				case 1: {
					if (x[i] < 4)szText = QString::asprintf("%dM", (int)(x[i] * 3));
					else szText = QString::asprintf("%dY", (int)x[i] - 3);
					break;
				}
				case 2: {
					if (x[i] < 4)szText = QString::asprintf("%dM", (int)(x[i] * 3));
					else {
						double m = x[i] - (int)(x[i]);
						if (m < m0) {
							szText = QString::asprintf("%dY", (int)x[i] - 3);
						}
						else {
							szText = QString::asprintf("%.2fY", ((int)(x[i] - 3) + (x[i] - (int)x[i])));
						}
					}
					break;
				}
				default: break;
				}

				int nFlag = Qt::TextDontClip | Qt::AlignCenter | Qt::AlignVCenter;
				QRectF rect(0, 0, 10000, 10000);
				QRectF measureRect = painter->boundingRect(rect, nFlag, szText);
				QPen oldPen = painter->pen();
				painter->setPen(QColor(128, 128, 128, 255));
				painter->drawText(X - measureRect.width() / 2, bottom, measureRect.width(), measureRect.height(), nFlag, szText);
				painter->setPen(oldPen);
			}
		}

		if (x)delete[] x;

		return true;
	}

	bool BondRateChart::drawGridYLines(BaseChartPainter* painter)
	{
		QString szValue;
		QRectF rfText;
		int i = 0;
		int nTextTop = 10000;//纵轴刻度文字
		int top = customPlot->yAxis->axisRect()->top();
		int bottom = customPlot->yAxis->axisRect()->bottom();
		int tickCount = (customPlot->yAxis->ticker()->tickCount() == 0 ? 5 : customPlot->yAxis->ticker()->tickCount());
		double step = (m_dMaxY - m_dMinY) / tickCount;
		double minY = m_dMinY;
		double maxY = m_dMaxY;
		QRectF rect(0, 0, 10000, 10000);
		int nFlag = Qt::TextDontClip | Qt::AlignLeft | Qt::AlignVCenter;

		while (1) 
		{
			float price = m_dMinY + step * i;
			int Y = customPlot->yAxis->coordToPixel(price);
			if (Y < top-1 || Y > bottom) break;
			if (Y <= bottom)
			{
				painter->drawLine(QLineF(customPlot->xAxis->axisRect()->left() - customPlot->yAxis->tickLabelPadding(), Y, customPlot->xAxis->axisRect()->right(), Y));
				if (((int)(step * 100)) % 10 > 0 || ((int)(minY * 100)) % 10 > 0 || ((int)(maxY * 100)) % 10 > 0) szValue = QString("%1").arg(price, 0, 'f', 2, '0');
				else szValue = QString("%1").arg(price, 0, 'f', 1, '0');

				QRectF measureRect = painter->boundingRect(rect, nFlag, szValue);
				if (nTextTop > Y + measureRect.height())
				{
					QPen oldPen = painter->pen();
					painter->setPen(QColor(128, 128, 128, 255));
					painter->drawText(customPlot->xAxis->axisRect()->left() - customPlot->yAxis->tickLabelPadding() + 2, Y - measureRect.height(), measureRect.width(), measureRect.height(), nFlag, szValue);
					painter->setPen(oldPen);
					nTextTop = Y - measureRect.height();
				}
			}
			i++;
			if (i > 100)
				break;
		}

		return true;
	}

	void BondRateChart::drawMouseMoveLine(BaseChartPainter* painter)
	{
		int x = mapFromGlobal(QCursor().pos()).x() - 8;
		int y = mapFromGlobal(QCursor().pos()).y() - 8;
		int top = customPlot->yAxis->axisRect()->top();
		int bottom = customPlot->yAxis->axisRect()->bottom();
		int left = customPlot->yAxis->axisRect()->left();
		int right = customPlot->yAxis->axisRect()->right();
		if (x < left || x > right || y < top || y > bottom)
		{
			return;
		}

		painter->drawLine(QLineF(x, bottom, x, top));
	}

	bool BondRateChart::customDraw(BaseChartPainter* painter, const QRect& rect)
	{
		if (type_All == mType)
		{
			painter->fillRect(rect, QColor(38, 55, 53));
			painter->setPen(QColor(205, 119, 4));
			painter->drawLine(QLineF(rect.left() + 6, rect.top() + rect.height() / 2, rect.left() + 14, rect.top() + rect.height() / 2));
			painter->drawLine(QLineF(rect.left() + 6, rect.top() + rect.height() / 2 + 1, rect.left() + 14, rect.top() + rect.height() / 2 + 1));
		}
		else
		{
			QRect rectBK = rect;
			rectBK.setRight(rectBK.left() + rect.width() / 2 - 2);
			painter->fillRect(rectBK, QColor(38, 55, 53));

			rectBK.setLeft(rectBK.left() + rect.width() / 2 + 2);
			rectBK.setRight(rect.right());
			painter->fillRect(rectBK, QColor(38, 55, 53));

			painter->setPen(QColor(0, 128, 253, 255));
			painter->setBrush(QColor(0, 128, 253, 255));
			painter->drawEllipse(rect.left() + 8, rect.top() + rect.height() / 2 - 2, 6, 6);

			painter->setPen(QColor(m_clrOutHour));
			painter->setBrush(QColor(m_clrOutHour));
			painter->drawEllipse(rect.left() + rect.width() / 2 + 8, rect.top() + rect.height() / 2 - 2, 6, 6);
		}

		return true;
	}

	void BondRateChart::inputData(CAnalysisYieldCurve* pYieldCurve)
	{
		CAnalysisYieldCurve* pData = (CAnalysisYieldCurve*)pYieldCurve;
		clearCurrentCurve();
		if (!pData) 
		{
			return;
		}

	//	m_chartDistData.m_Stream.m_list = pData->m_Stream.m_list;
		FIELDCOPY(m_chartDistData.m_Curve.m_CurveName, pData->m_Curve.m_CurveName);
		FIELDCOPY(m_chartDistData.m_Curve.m_CurveType, pData->m_Curve.m_CurveType);
		FIELDCOPY(m_chartDistData.m_Curve.m_CurveName_En, pData->m_Curve.m_CurveName_En);
		m_chartDistData.m_Curve.m_Date = pData->m_Curve.m_Date;

		if (type_All == mType)
		{
			m_chartDistData.m_Curve.m_List = pData->m_Curve.m_List;
			m_chartDistData.m_Stream.m_list.clear();
			return;
		}
		else
		{
			const int cn_near_number = 4;
			if (pData->m_Curve.m_List.size() <= cn_near_number) {
				m_chartDistData.m_Curve.m_List = pData->m_Curve.m_List;
				return;
			}
			std::map<int, std::list<xQBAYieldCurveUnit_c>> mapCurve;
			for (std::list<xQBAYieldCurveUnit_c>::const_iterator itr = pData->m_Curve.m_List.begin();
				itr != pData->m_Curve.m_List.end(); itr++) {
				mapCurve[abs(GetDate(itr->m_Period) - m_lRemain)].push_back(*itr);
			}
			int nLoop = 0;
			for (std::map<int, std::list<xQBAYieldCurveUnit_c>>::const_iterator itrMp = mapCurve.begin();
				itrMp != mapCurve.end(); itrMp++) {
				if (nLoop >= cn_near_number) break;
				for (std::list<xQBAYieldCurveUnit_c>::const_iterator itUnit = itrMp->second.begin();
					itUnit != itrMp->second.end(); itUnit++) {
					m_chartDistData.m_Curve.m_List.push_back(*itUnit);
					nLoop++;
					if (nLoop >= cn_near_number) break;
				}
			}
		}
	}

	void BondRateChart::refreshData()
	{
		QB_CHECK_RETURN_VOID1(customPlot && customPlot->graph(0) && customPlot->graph(1) && customPlot->graph(2) && bcte && bcde);

		m_CurveShow.clear();
		m_StreamShow.clear();

		BONDRATE br;
		QString szTemp, szUnit, szValue;
		std::list<xQBAYieldCurveUnit_c>::const_iterator it;
		for (it = m_chartDistData.m_Curve.m_List.begin(); it != m_chartDistData.m_Curve.m_List.end(); it++) {
			szTemp = it->m_Period;
			szUnit = szTemp.right(1);
			if (szUnit == "D") {
				szValue = szTemp.left(szTemp.length() - 1);
				br.expire = szValue.toFloat() * 4 / 365;
			}
			else if (szUnit == "M") {
				szValue = szTemp.left(szTemp.length() - 1);
				br.expire = szValue.toFloat() * 4 / 12;
			}
			else if (szUnit == "Y") {
				szValue = szTemp.left(szTemp.length() - 1);
				br.expire = szValue.toFloat();
				if (br.expire > 0.5)br.expire += 3;
			}
			else {
				szValue = szTemp;
				br.expire = szValue.toFloat();
				//	if (br.expire > 0.5)br.expire += 3;
			}
			br.price = it->m_Yield;
			m_CurveShow.push_back(br);
		}
		m_CurveShow.sort();

		if (m_CurveShow.size() < 6)
		{
			bcde->setEnable(false);
		}
		else
		{
			bcde->setEnable(true);
		}

		bool bFirst = false;
		if (0.0 == m_dOriginMaxX)
		{
			bFirst = true;
		}

		m_dOriginMaxX = max(m_dOriginMaxX, m_CurveShow.size() - 1);
		m_dOriginMaxX = min(m_dOriginMaxX, m_CurveShow.size() - 1);

		int begin = 0, end = 0;
		if (type_All == mType)
		{
			begin = m_nBegin;
			end = m_nEnd;
		}
		else
		{
			begin = m_nDealBegin;
			end = m_nDealEnd;
		}

		if (begin > 0 && begin < (int)m_CurveShow.size() - 1)
		{
			auto itBegin = m_CurveShow.begin();
			auto itEnd = m_CurveShow.begin();
			std::advance(itEnd, begin);
			m_CurveShow.erase(itBegin, itEnd);
		}
		if (end - begin > 0 && end - begin < (int)m_CurveShow.size() - 1)
		{
			auto itBegin = m_CurveShow.begin();
			auto itEnd = m_CurveShow.end();
			std::advance(itBegin, end - begin);
			m_CurveShow.erase(itBegin, itEnd);
		}

		QVector<double>	vctX, vctY;
		for (auto itCurve = m_CurveShow.begin(); itCurve != m_CurveShow.end(); itCurve++) {

			vctX.push_back(itCurve->expire);
			vctY.push_back(itCurve->price);
		}

		BONDTRADEINFO bti;
		CBondContainer& container = CBondContainer::instance();
		std::list<MarketStreamInfo>::iterator it2;
		time_t t = ServerTimeMgr::instance().serverTime();
		for (it2 = m_chartDistData.m_Stream.m_list.begin(); it2 != m_chartDistData.m_Stream.m_list.end(); it2++) {
			int bondIndex = container.GetBondIndex(it2->m_body.m_bondkey, it2->m_body.m_listedmarket);
			if (!container.IsValidIndex(bondIndex))continue;
			const CBondInfo& info = container.ElementAtR(bondIndex);
			memset(&bti, 0, sizeof(BONDTRADEINFO));
			if (atoi(it2->m_body.m_exercise) == 1) {//到期
				bti.expire = info.GetRemainYear(t);
			}
			else {//行权
				bti.expire = info.GetRemainYearToOption(t);
			}

			if (bti.expire < 1.0000)bti.expire *= 4;
			else bti.expire += 3;
			bti.moditytime = it2->m_modify_time;
			if (strlen(it2->m_body.m_yield) > 0) {
				bti.price = atof(it2->m_body.m_yield);
				FIELDCOPY(bti.sprice, it2->m_body.m_yield);
			}
			bti.brokerid = atoi(it2->m_company_id);
			FIELDCOPY(bti.operate, it2->m_operate);
			FIELDCOPY(bti.code, info.GetBondCode());
			FIELDCOPY(bti.key, info.GetBondKey());
			FIELDCOPY(bti.shortname, info.GetBondShortName());
			FIELDCOPY(bti.remain, info.GetRemainPeriod(t));
			FIELDCOPY(bti.rating, info.GetIssuerRating());
			m_StreamShow.push_back(bti);
		}
		m_StreamShow.sort();

		m_nLinePNum = m_CurveShow.size();
		if (m_nLinePNum > 0) {
			if (m_pLineP)delete[] m_pLineP;
			m_pLineP = new QPointF[m_nLinePNum];
		}
		m_nPointNum = m_StreamShow.size();
		if (m_nPointNum > 0) {
			if (m_pPoints)delete[] m_pPoints;
			m_pPoints = new QPointF[m_nPointNum];
		}

		customPlot->graph(0)->setData(vctX, vctY);

		m_dMinX = 0;
		m_dMaxX = 53;
		if (m_CurveShow.size() > 0) {
			m_dMaxX = m_CurveShow.back().expire;
			m_dMinX = m_CurveShow.front().expire;
			if (m_StreamShow.size() > 0) m_dMaxX = max(m_dMaxX, m_StreamShow.back().expire);
		}

		GetShowLimit(m_dMinX, m_dMaxX, m_dMinY, m_dMaxY);
		customPlot->yAxis->setRange(m_dMinY, m_dMaxY);

		double dExt = (m_dMaxX - m_dMinX) / 20;
		customPlot->xAxis->setRange(m_dMinX, m_dMaxX + dExt);

		int i = 0;
		std::list<BONDRATE>::iterator it3;
		for (it3 = m_CurveShow.begin(); it3 != m_CurveShow.end(); it3++, i++) {
			m_pLineP[i].setX(customPlot->xAxis->coordToPixel(it3->expire));
			m_pLineP[i].setY(customPlot->yAxis->coordToPixel(it3->price));
		}

		i = 0;
		QVector<double> vctInX, vctInY, vctOutX, vctOutY;
		std::list<BONDTRADEINFO>::iterator it4;
		for (it4 = m_StreamShow.begin(); it4 != m_StreamShow.end(); it4++, i++) {
			if (i >= m_nPointNum) break;

			if (t - it4->moditytime <= 3600) {
				vctInX.push_back(it4->expire);
				vctInY.push_back(it4->price);
			}
			else if (t - it4->moditytime > 3600) {
				vctOutX.push_back(it4->expire);
				vctOutY.push_back(it4->price);
			}

			m_pPoints[i].setX(customPlot->xAxis->coordToPixel(it4->expire));
			m_pPoints[i].setY(customPlot->yAxis->coordToPixel(it4->price));
		}

		if (type_All == mType)
		{
			customPlot->graph(1)->setVisible(false);
			customPlot->graph(2)->setVisible(false);

			QString qText = tr("收益率");
			bcte->setText(qText);

			if (m_CurveShow.size() > 0 && (m_dDragLeft == 0.0 && m_dDragRight == 0.0 || bFirst))
			{
				int end = m_nEnd;
				if (m_nEnd == 0)
				{
					end = m_dOriginMaxX;
				}

				bcde->setPos(getXPos_Value(m_nBegin), getXPos_Value(end));
			}
		}
		else
		{
			customPlot->graph(1)->setVisible(true);
			customPlot->graph(2)->setVisible(true);

			customPlot->graph(1)->setData(vctOutX, vctOutY);
			customPlot->graph(2)->setData(vctInX, vctInY);

			QString qText1 = tr("当日成交(一小时内)");
			QString qText2 = tr("当日成交(一小时前)");
			bcte->setText(qText1, qText2);

			if (m_CurveShow.size() > 0 && (m_dDealDragLeft == 0.0 && m_dDealDragRight == 0.0 || bFirst))
			{
				int end = m_nDealEnd;
				if (m_nDealEnd == 0)
				{
					end = m_dOriginMaxX;
				}

				bcde->setPos(getXPos_Value(m_nDealBegin), getXPos_Value(end));
			}
		}

		customPlot->replot(BaseChartCustomPlot::rpQueuedReplot);
	}

	void BondRateChart::clearCurrentCurve()
	{
		m_chartDistData.m_Curve.m_List.clear();
		memset(m_chartDistData.m_Curve.m_CurveType, 0, sizeof(char) * 32);
		memset(m_chartDistData.m_Curve.m_CurveName, 0, sizeof(char) * 64);
		memset(m_chartDistData.m_Curve.m_CurveName_En, 0, sizeof(char) * 256);
	}

	void BondRateChart::GetShowLimit(double fMinXShow, double fMaxXShow, double& fMinYShow, double& fMaxYShow) {
		fMinYShow = 1000;
		fMaxYShow = -1000;

		bool bBegin = true;
		std::list<BONDRATE>::iterator it;
		int i = 0;
		bool bend = false;
		for (it = m_CurveShow.begin(); it != m_CurveShow.end(); it++, i++) {
			if (it->expire >= fMinXShow) {
				if (it->expire <= fMaxXShow) {
					if (bBegin) {
						if (i == 0) {
							fMinYShow = min(fMinYShow, it->price);
							fMaxYShow = max(fMaxYShow, it->price);
						}
						else {
							it--;
							BONDRATE lastbr = *it;
							it++;
							double fp = (lastbr.price - it->price) * (fMinXShow - it->expire) / (lastbr.expire - it->expire) + it->price;
							fMinYShow = min(fMinYShow, fp);
							fMaxYShow = max(fMaxYShow, fp);
							fMinYShow = min(fMinYShow, it->price);
							fMaxYShow = max(fMaxYShow, it->price);
						}
						bBegin = false;
					}
					else {
						fMinYShow = min(fMinYShow, it->price);
						fMaxYShow = max(fMaxYShow, it->price);
					}
				}
				else {
					if (!bend) {
						if (i == 0) {
							fMinYShow = min(fMinYShow, it->price);
							fMaxYShow = max(fMaxYShow, it->price);
						}
						else {
							if (bBegin) {
								it--;
								BONDRATE lastbr = *it;
								it++;
								double fp = (it->price - lastbr.price) * (fMaxXShow - lastbr.expire) / (it->expire - lastbr.expire) + lastbr.price;
								fMinYShow = min(fMinYShow, fp);
								fMaxYShow = max(fMaxYShow, fp);
								fp = (it->price - lastbr.price) * (fMinXShow - lastbr.expire) / (it->expire - lastbr.expire) + lastbr.price;
								fMinYShow = min(fMinYShow, fp);
								fMaxYShow = max(fMaxYShow, fp);
							}
							else {
								it--;
								BONDRATE lastbr = *it;
								it++;
								double fp = (it->price - lastbr.price) * (fMaxXShow - lastbr.expire) / (it->expire - lastbr.expire) + lastbr.price;
								fMinYShow = min(fMinYShow, fp);
								fMaxYShow = max(fMaxYShow, fp);
							}
						}
						bend = true;
					}
				}
			}
		}

		std::list<BONDTRADEINFO>::iterator it2;
		for (it2 = m_StreamShow.begin(); it2 != m_StreamShow.end(); it2++) {
			if (it2->expire >= fMinXShow && it2->expire <= fMaxXShow) {
				fMinYShow = min(fMinYShow, it2->price);
				fMaxYShow = max(fMaxYShow, it2->price);
			}
		}

		if (fMaxYShow < 0) {
			fMinYShow = 3;
			fMaxYShow = 7;
			return;
		}

		if (fMinYShow >= 0) fMinYShow = (int)(fMinYShow * 4) / 4.0;
		else fMinYShow = (int)(fMinYShow * 4) / 4.0 - 0.25;
		fMaxYShow = (int)(fMaxYShow * 4) / 4.0 + 0.25;
	}

	void BondRateChart::DecodeMarketStreamUnit(MarketStreamInfo& stInfo, const xQBMarketStreamUnit_c& unit)
	{
		memset(&stInfo, 0, sizeof(MarketStreamInfo));
		FIELDCOPY(stInfo.m_company_id, unit.m_company_id);
		FIELDCOPY(stInfo.m_dept, unit.m_dept);
		FIELDCOPY(stInfo.m_type, unit.m_type);
		FIELDCOPY(stInfo.m_operate, unit.m_operate);
		FIELDCOPY(stInfo.m_status, unit.m_status);
		FIELDCOPY(stInfo.m_body.m_bondkey, unit.m_body2.m_bondkey);
		FIELDCOPY(stInfo.m_body.m_listedmarket, unit.m_body2.m_listedmarket);
		FIELDCOPY(stInfo.m_body.m_price, SSTools::PriceRemoveZero(unit.m_body2.m_price, 0).c_str());
		FIELDCOPY(stInfo.m_body.m_volume, unit.m_body2.m_volume);
		FIELDCOPY(stInfo.m_body.m_fullPrice, unit.m_body2.m_fullPrice);
		FIELDCOPY(stInfo.m_body.m_cleanPrice, unit.m_body2.m_cleanPrice);
		FIELDCOPY(stInfo.m_body.m_yield, unit.m_body2.m_yield);
		FIELDCOPY(stInfo.m_body.m_rebate, unit.m_body2.m_rebate);
		FIELDCOPY(stInfo.m_body.m_return_point, unit.m_body2.m_return_point);
		FIELDCOPY(stInfo.m_body.m_id, unit.m_body2.m_id);
		FIELDCOPY(stInfo.m_body.m_dealStatus, unit.m_body2.m_dealStatus);
		FIELDCOPY(stInfo.m_body.m_exercise, unit.m_body2.m_exercise);
		stInfo.m_body.m_createTime = unit.m_body2.m_createTime;
		stInfo.m_modify_time = unit.m_modify_time;
		stInfo.m_create_time = unit.m_create_time;
		stInfo.m_indexID = unit.m_indexID;
	}

	int BondRateChart::GetDate(const char* cDate)
	{
		if (!cDate || strlen(cDate) <= 0) return 0;
		QString szTemp, szUnit, szValue;
		szTemp = QString("%1").arg(cDate);
		szUnit = szTemp.right(1);
		szValue = szTemp.left(szTemp.length() - 1);
		if (szUnit == "Y") {
			return szValue.toInt() * 365;
		}
		else if (szUnit == "M") {
			return szValue.toInt() * 30;
		}
		else if (szUnit == "D") {
			return szValue.toInt();
		}
		else {
			return 0;
		}
	}

	double BondRateChart::getXPos_Value(double value)
	{
		QB_CHECK_RETURN_VALUE(bcde, 0);

		if (m_dOriginMaxX - m_dOriginMinX == 0) return 0;
		return (value - m_dOriginMinX) / (m_dOriginMaxX - m_dOriginMinX) * bcde->rect().width();
	}

	void BondRateChart::StartTimer()
	{
		QB_CHECK_RETURN_VOID1(mTimer);
		mTimer->start();
	}

	void BondRateChart::StopTimer()
	{
		QB_CHECK_RETURN_VOID1(mTimer);
		mTimer->stop();
	}

	void BondRateChart::onTimer()
	{
		if (mType == type_All) {
			StopTimer();
		}
		else {
			if (m_chartDistData.m_Curve.m_List.size() > 0 || m_chartDistData.m_Stream.m_list.size() > 0) {
				refreshData();
			}
		}
	}

	void BondRateChart::paintEvent(QPaintEvent* event)
	{
		QStylePainter painter(this);

		painter.fillRect(rect(), StyleMgr::instance().color("BasicPlate"));
	}

	void BondRateChart::leaveEvent(QEvent* event)
	{
		QB_CHECK_RETURN_VOID1(customPlot);

		customPlot->replot();
	}

	void BondRateChart::onMouseMove(QMouseEvent* event)
	{
		QB_CHECK_RETURN_VOID1(customPlot && customPlot->graph(0) && m_pLineP);

		double dm = customPlot->graph(0)->selectTest(event->pos(), false);
		if (0 < dm && 2 > dm)
		{
			QPen pen(QColor(225, 146, 0));
			pen.setWidth(2);
			customPlot->graph(0)->setPen(pen);
		}
		else
		{
			QPen pen(QColor(205, 119, 4));
			pen.setWidth(1);
			customPlot->graph(0)->setPen(pen);
		}

		customPlot->replot();

		int left = customPlot->yAxis->axisRect()->left();
		int right = customPlot->yAxis->axisRect()->right();

		int x = mapFromGlobal(event->screenPos().toPoint()).x() - 8;
		int y = mapFromGlobal(event->screenPos().toPoint()).y() - 8;

		QPointF* p = m_pPoints;
		int nHot = -1;

		std::list<int> lp;
		for (int i = 0; i < m_nPointNum; i++, p++) {
			if (p->x() >= left && p->x() <= right) {
				if ((x - p->x()) * (x - p->x()) + (y - p->y()) * (y - p->y()) < 36) {
					lp.push_back(i);
				}
			}
		}
		if (lp.size() > 0) {
			CBondTradeInfoList dataList;
			int i = 0;
			std::list<int>::iterator iti;
			std::list<BONDTRADEINFO>::iterator it;
			int nLast = -1;
			int nMinT = -1;
			time_t t = ServerTimeMgr::instance().serverTime();
			QString strComparePrc;
			for (iti = lp.begin(); iti != lp.end(); iti++) {
				i = 0;
				for (it = m_StreamShow.begin(); it != m_StreamShow.end(); it++, i++) {
					if (i == *iti) {
						int dt = t - it->moditytime;
						if (nMinT < 0) {
							nMinT = dt;
							nLast = i;
							strComparePrc = QString("%1").arg(it->sprice);
						}
						else if (dt < nMinT) {
							nMinT = dt;
							nLast = i;
							strComparePrc = QString("%1").arg(it->sprice);
						}
						break;
					}
				}
			}
			if (nLast >= 0) {
				i = 0;
				for (it = m_StreamShow.begin(); it != m_StreamShow.end(); it++, i++) {
					if (i == nLast) {
						int nNumb = 0;
						for (std::list<BONDTRADEINFO>::iterator itLoop = m_StreamShow.begin(); itLoop != m_StreamShow.end(); itLoop++) {
							QString strCmp(itLoop->sprice);
							if (strComparePrc == strCmp) {
								nNumb++;
							}
						}

						m_nHotPoint = i;
						p = &m_pPoints[i];

						QString szTip;
						BONDTRADEINFO bti;
						bti = *it;

						if (bti.brokerid == 50) {
							szTip = QString("收益率 %1%").arg(it->sprice);

							std::vector<QBTipCustomItem> vctCustomItem;
							QBTipCustomItem item;
							item.row = 0;
							item.col = 1;
							item.clrNormal = QColor(223, 174, 76, 255);
							vctCustomItem.push_back(item);
							QBTips::showText(event->screenPos().toPoint(), szTip, this, &vctCustomItem);
						}
						else {
							szTip = QString("收益率 %1% 成交笔数 %2").arg(it->sprice).arg(nNumb);

							std::vector<QBTipCustomItem> vctCustomItem;
							QBTipCustomItem item;
							item.row = 0;
							item.col = 1;
							item.clrNormal = QColor(223, 174, 76, 255);
							vctCustomItem.push_back(item);
							item.col = 3;
							vctCustomItem.push_back(item);
							QBTips::showText(event->screenPos().toPoint(), szTip, this, &vctCustomItem);
						}

						break;
					}
				}
				return;
			}
		}

		p = m_pLineP;
		for (int i = 0; i < m_nLinePNum; i++, p++) {
			if (p->x() >= left && p->x() <= right) {
				if ((x - p->x()) * (x - p->x()) + (y - p->y()) * (y - p->y()) < 16) {
					if (m_nHotPoint != i) {
						m_nHotPoint = i;

						QString szTip;
						std::list<BONDRATE>::iterator it;
						int j = 0;
						for (it = m_CurveShow.begin(); it != m_CurveShow.end(); it++, j++) {
							if (i == j) {
								if (it->expire >= 4) {
									if ((it->expire - (int)(it->expire)) < 0.02) {
										szTip = QString::asprintf("%dY %.4f%%  ", (int)it->expire - 3, it->price);
									}
									else {
										szTip = QString::asprintf("%.1fY %.4f%%  ", it->expire - 3, it->price);
									}
								}
								else {
									if (it->expire <= 0.0001) {
										szTip = QString::asprintf("0D %.4f%%  ", it->price);
									}
									else if (it->expire < 0.333) {
										szTip = QString::asprintf("%dD %.4f%%  ", (int)(it->expire * 3 * 30 + 0.5f), it->price);
									}
									else {
										szTip = QString::asprintf("%dM %.4f%%  ", (int)(it->expire * 3 + 0.5f), it->price);
									}
								}
								break;
							}
						}
						if (szTip.length() > 0) {
							std::vector<QBTipCustomItem> vctCustomItem;
							QBTipCustomItem item;
							item.row = 0;
							item.col = 1;
							item.clrNormal = QColor(223, 174, 76, 255);
							vctCustomItem.push_back(item);
							QBTips::showText(event->screenPos().toPoint(), szTip, this, &vctCustomItem);
						}
					}
					return;
				}
			}
		}

		if (m_nHotPoint >= 0) {
			m_nHotPoint = -1;
			QBTips::hideTip();
		}
	}
}
